var exec = require("child_process").exec;
var path = require("path");

module.exports = function(grunt) {

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* UTILs
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    var copyFiles = function(srcPath, destPath, fileNames) {
        fileNames.forEach(function(fileName) {
            var from = path.join(srcPath, fileName);
            var to = path.join(destPath, fileName);
            grunt.log.writeln("Copy From: " + from + ", To: " + to);
            grunt.file.copy(from, to);
        });
    };

    var copyDir = function(src, dest, fileFilter, dirFilter) {
        grunt.log.writeln("Copying dir from: " + src + ", to: " + dest);

        grunt.file.recurse(src, function(abspath, rootdir, subdir, filename) {
            if (dirFilter) {
                for (var dfKey in dirFilter) {
                    if (dirFilter.hasOwnProperty(dfKey) && abspath.indexOf(dirFilter[dfKey]) !== -1) {
                        return;
                    }
                }
            }
            if (fileFilter) {
                for (var ffKey in fileFilter) {
                    if (fileFilter.hasOwnProperty(ffKey) && filename.indexOf(fileFilter[ffKey]) !== -1) {
                        return;
                    }
                }
            }

            var targetPath = subdir ? path.join(dest, subdir, filename) : path.join(dest, filename);
            // grunt.log.writeln("Copying file to: " + targetPath);
            grunt.file.copy(abspath, targetPath);
        });
    };

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* CONFIGs
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    var assetJsPath = "./js/";
    var scriptPath = "./resources/scripts/";
    var componentPath = "./components/";

    var assetCssPath = "./css/";
    var stylePath = "./resources/styles/";
    var tempCssPath = "./tmp/";

    var assetHtmlPath = "./view/";
    var templatePath = "./resources/templates/";

    var assetImgPath = "./img/";
    var imagesPath = "./resources/images/";

    var copyConfigs = [
        {
            "src": componentPath,
            "dest": assetJsPath,
            "files": [
                ["angular", "angular", ["angular.min.js", "angular.min.js.map"]],
                ["angular-animate", "angular", ["angular-animate.min.js"]],
                ["angular-bootstrap", "angular", ["ui-bootstrap-tpls.min.js"]],
                ["angular-route", "angular", ["angular-route.min.js"]],
                ["angular-route-segment/build", "angular", ["angular-route-segment.min.js"]],
                ["bootstrap/dist/js", "bootstrap", ["bootstrap.min.js"]],
                ["d3", "d3", ["d3.min.js"]],
                ["jquery/dist", "jquery", ["jquery.min.js", "jquery.min.map"]],
                ["moment/min", "moment", ["langs.min.js", "moment.min.js"]],
                ["prefix-free", "prefix-free", ["prefixfree.min.js"]],
                ["socket.io-client/dist", "socket.io", ["socket.io.min.js"]],
                ["swfobject/swfobject", "swfobject", ["expressInstall.swf", "swfobject.js"]],
                ["pako/dist", "pako", ["pako.min.js"]]
            ]
        }, {
            "src": scriptPath,
            "dest": assetJsPath,
            "files": [
                ["libs/jquery.json", "jquery.json", ["jquery.json.min.js"]]
            ]
        }, {
            "src": componentPath,
            "dest": assetCssPath,
            "files": [
                ["angular", "angular", ["angular-csp.css"]],
                ["bootstrap/dist/css", "bootstrap/styles", ["bootstrap.min.css", "bootstrap-theme.min.css"]],
                ["bootstrap/dist/fonts", "bootstrap/fonts",
                    ["glyphicons-halflings-regular.eot", "glyphicons-halflings-regular.svg",
                    "glyphicons-halflings-regular.ttf", "glyphicons-halflings-regular.woff"]]
            ]
        }
    ];
    var uglifyConfigs = [
        {
            "src": componentPath,
            "dest": assetJsPath,
            "files": {
                "jquery.cookie/jquery.cookie.min.js": ["jquery.cookie/jquery.cookie.js"],
                "requirejs/require.min.js": ["requirejs/require.js"],
                "spin/spin.min.js": ["spin.js/spin.js"],
                "angular/angular-scroll-glue.min.js": ["angularjs-scroll-glue/src/scrollglue.js"],
                "requirejs/text.min.js": ["requirejs-plugins/lib/text.js"],
                "requirejs/json.min.js": ["requirejs-plugins/src/json.js"],
                "base64js/base64js.min.js": ["base64js/base64js.js"]
            }
        }, {
            "src": scriptPath,
            "dest": assetJsPath,
            "files": {
                "sz/sns/SzSnsFacebook.min.js": ["lib-sz/sns/SzSnsFacebook.js"],
                "sz/sns/SzSnsSina.min.js": ["lib-sz/sns/SzSnsSina.js"],
                "sz/sns/SzSnsVk.min.js": ["lib-sz/sns/SzSnsVk.js"],
                "sz/sns/SzSnsOgz.min.js": ["lib-sz/sns/SzSnsOgz.js"],
                "sz/SzLib.min.js": ["lib-sz/SzLib.js"],
                "sz/SzSns.min.js": ["lib-sz/SzSns.js"],
                "sz/SzSpin.min.js": ["lib-sz/SzSpin.js"],
                "app/app.min.js": ["app/app.js"],
                "gm/gm.min.js": ["gm/gm.js"]
            }
        }, {
            "src": assetJsPath,
            "dest": assetJsPath,
            "files": {
                "boot.min.js": ["boot.min.js"]
            }
        }
    ];
    var requireJsPathConfigs = {
        "angular": assetJsPath + "angular/angular.min",
        "angular-animate": assetJsPath + "angular/angular-animate.min",
        "angular-bootstrap": assetJsPath + "angular/ui-bootstrap-tpls.min",
        "angular-route": assetJsPath + "angular/angular-route.min",
        "angular-route-segment": assetJsPath + "angular/angular-route-segment.min",
        "angular-scroll-glue": assetJsPath + "angular/angular-scroll-glue.min",
        "d3": assetJsPath + "d3/d3.min",
        "bootstrap": assetJsPath + "bootstrap/bootstrap.min",
        "jquery": assetJsPath + "jquery/jquery.min",
        "moment": assetJsPath + "moment/moment.min",
        "moment.langs": assetJsPath + "moment/langs.min",
        "prefixfree": assetJsPath + "prefix-free/prefixfree.min",
        "spin": assetJsPath + "spin/spin.min",
        "swfobject": assetJsPath + "swfobject/swfobject",
        "jquery.json": assetJsPath + "jquery.json/jquery.json.min",
        "jquery.cookie": assetJsPath + "jquery.cookie/jquery.cookie.min",
        "text": assetJsPath + "requirejs/text.min",
        "json": assetJsPath + "requirejs/json.min",
        "SzSnsFacebook": assetJsPath + "sz/sns/SzSnsFacebook.min",
        "SzSnsSina": assetJsPath + "sz/sns/SzSnsSina.min",
        "SzSnsVk": assetJsPath + "sz/sns/SzSnsVk.min",
        "SzSnsOgz": assetJsPath + "sz/sns/SzSnsOgz.min",
        "SzLib": assetJsPath + "sz/SzLib.min",
        "SzSns": assetJsPath + "sz/SzSns.min",
        "SzSpin": assetJsPath + "sz/SzSpin.min",
        "socket.io": assetJsPath + "socket.io/socket.io.min",
        "pako": assetJsPath + "pako/pako.min",
        "base64js": assetJsPath + "base64js/base64js.min",
        "app": assetJsPath + "app/app.min"
    };
    var requireJsShimConfigs = {
        "jquery": {"exports": "$"},
        "bootstrap": {"deps": ["jquery"]},
        "jquery.json": {"deps": ["jquery"]},
        "jquery.cookie": {"deps": ["jquery"]},
        "spin": {"exports": "Spinner"},
        "angular" : {"exports" : "angular"},
        "angular-animate": ["angular"],
        "angular-bootstrap": ["angular"],
        "angular-route": ["angular"],
        "angular-route-segment": ["angular"],
        "angular-scroll-glue": ["angular"]
    };
    // var syncConf = {};
    // if (!grunt.file.exists("./grunt-watch-ftp.json")) {
    //     grunt.error.fatal("Required deployment config file not found: ./grunt-watch-ftp.json");
    // } else {
    //     syncConf = grunt.file.readJSON("./grunt-watch-ftp.json");
    // }

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* GRUNT Configs
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.initConfig({
        "clean": {
            "all" : [
                assetJsPath + "*",
                assetCssPath + "*",
                assetHtmlPath + "*",
                componentPath + "*"
            ],
            "css" : [
                tempCssPath,
                assetCssPath + "*.css"
            ]
        },
        "jshint": {
            "options": {
                "reporter": require("jshint-stylish"),
                "-W014": true
            },
            "all": [
                scriptPath + "admin/**/*.js",
                scriptPath + "app/**/*.js",
                scriptPath + "lib-sz/**/*.js",
                scriptPath + "boot.js"
            ]
        },
        "uglify": {
            "all": {
                "files": {}
            }
        },
        "less": {
            "all": {
                "expand": true,
                "cwd": stylePath,
                "src": ["**/*.less"],
                "dest": assetCssPath,
                "ext": ".css"
            }
        },
        "cssmin": {
            "all": {
                "expand": true,
                "cwd": assetCssPath,
                "src": ["**/*.css", "!**/*.min.css", "!angular/*.css"],
                "dest": assetCssPath,
                "ext": ".css"
            }
        },
        "htmlmin": {
            "all": {
                "options": {
                    "removeComments": true,
                    "collapseWhitespace": true,
                    "collapseBooleanAttributes": true
                },
                "expand": true,
                "cwd": templatePath,
                "src": ["**/*.html"],
                "dest": assetHtmlPath,
                "ext": ".html"
            }
        },
        "sprite": {
            "en_us": {
                'algorithm': 'binary-tree',
                'src': [imagesPath + 'en_US/**/*.png'],
                'destImg': assetImgPath + 'en_US/sprite.png',
                'destCSS': tempCssPath + 'en_US/sprite_positions.css'
            },
            "fr_fr": {
                'algorithm': 'binary-tree',
                'src': [imagesPath + 'fr_FR/**/*.png'],
                'destImg': assetImgPath + 'fr_FR/sprite.png',
                'destCSS': tempCssPath + 'fr_FR/sprite_positions.css'
            },
            "ge_ge": {
                'algorithm': 'binary-tree',
                'src': [imagesPath + 'ge_GE/**/*.png'],
                'destImg': assetImgPath + 'ge_GE/sprite.png',
                'destCSS': tempCssPath + 'ge_GE/sprite_positions.css'
            },
            "spa_spa": {
                'algorithm': 'binary-tree',
                'src': [imagesPath + 'spa_SPA/**/*.png'],
                'destImg': assetImgPath + 'spa_SPA/sprite.png',
                'destCSS': tempCssPath + 'spa_SPA/sprite_positions.css'
            },
            "por_por": {
                'algorithm': 'binary-tree',
                'src': [imagesPath + 'por_POR/**/*.png'],
                'destImg': assetImgPath + 'por_POR/sprite.png',
                'destCSS': tempCssPath + 'por_POR/sprite_positions.css'
            },
            "zh_cn": {
                'algorithm': 'binary-tree',
                'src': [imagesPath + 'zh_CN/**/*.png'],
                'destImg': assetImgPath + 'zh_CN/sprite.png',
                'destCSS': tempCssPath + 'zh_CN/sprite_positions.css'
            }
            ,
            "ru_ru": {
                'algorithm': 'binary-tree',
                'src': [imagesPath + 'ru_RU/**/*.png'],
                'destImg': assetImgPath + 'ru_RU/sprite.png',
                'destCSS': tempCssPath + 'ru_RU/sprite_positions.css'
            }
        },
        "concat": {
            "en_us": {
                "src": [
                    assetCssPath + "main.css",
                    tempCssPath + "en_US/sprite_positions.css"
                ],
                "dest": assetCssPath + "en_US/main.css"
            },
            "fr_fr": {
                "src": [
                    assetCssPath + "main.css",
                    tempCssPath + "fr_FR/sprite_positions.css"
                ],
                "dest": assetCssPath + "fr_FR/main.css"
            },
            "ge_ge": {
                "src": [
                    assetCssPath + "main.css",
                    tempCssPath + "ge_GE/sprite_positions.css"
                ],
                "dest": assetCssPath + "ge_GE/main.css"
            },
            "spa_spa": {
                "src": [
                    assetCssPath + "main.css",
                    tempCssPath + "spa_SPA/sprite_positions.css"
                ],
                "dest": assetCssPath + "spa_SPA/main.css"
            },
            "por_por": {
                "src": [
                    assetCssPath + "main.css",
                    tempCssPath + "por_POR/sprite_positions.css"
                ],
                "dest": assetCssPath + "por_POR/main.css"
            },
            "zh_cn": {
                "src": [
                    assetCssPath + "main.css",
                    tempCssPath + "zh_CN/sprite_positions.css"
                ],
                "dest": assetCssPath + "zh_CN/main.css"
            },
            "ru_ru": {
                "src": [
                    assetCssPath + "main.css",
                    tempCssPath + "ru_RU/sprite_positions.css"
                ],
                "dest": assetCssPath + "ru_RU/main.css"
            }
        },
        "watch": {
            "all": {
                "files": [
                    scriptPath + "**/*.js",
                    stylePath + "**/*.less",
                    templatePath + "**/*.html"
                ],
                "tasks": ["Task_WatchUpgrade"],
                "options": {
                    spawn: false
                }
            }
        },
        // "sftp": {
        //     "all": {
        //         "files": {
        //             "./": ["js/**", "css/**", "img/**", "view/**"]
        //         },
        //         "options": {
        //             "path": syncConf.remote.path,
        //             "host": syncConf.remote.host,
        //             "username": syncConf.remote.username,
        //             "password": syncConf.remote.password,
        //             "showProgress": true,
        //             "createDirectories": true
        //         }
        //     }
        // }
    });

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* TASKs
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* CLEAN
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks("grunt-contrib-clean");
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* INIT
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    var Task_Init = function() {
        if (!grunt.file.exists(assetJsPath)) {
            grunt.file.mkdir(assetJsPath);
        }
        if (!grunt.file.exists(assetCssPath)) {
            grunt.file.mkdir(assetCssPath);
        }
        if (!grunt.file.exists(componentPath)) {
            grunt.file.mkdir(componentPath);
        }
    };
    grunt.registerTask("Task_Init", Task_Init);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* BOWER
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    var Task_BowerInstall = function() {
        var done = this.async();
        exec("bower install", {cwd: "./"}, function(err, stdout, stderr) {
            if (err) {
                grunt.fail.fatal(err);
            }
            grunt.log.write(stdout);
            done();
        });
    };
    grunt.registerTask("Task_BowerInstall", Task_BowerInstall);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* JSHINT
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks("grunt-contrib-jshint");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* CONCAT JS
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks("grunt-contrib-concat");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* PREPARE COMPONENTS
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    var Task_CopyComponents = function() {
        copyConfigs.forEach(function(config) {
            config.files.forEach(function(fileConfig) {
                copyFiles(
                    path.join(config.src, fileConfig[0]),
                    path.join(config.dest, fileConfig[1]),
                    fileConfig[2]
                );
            });
        });
    };
    grunt.registerTask("Task_CopyComponents", Task_CopyComponents);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* REQUIRE JS CONFIG
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    var Task_PrepareRequireJsConfig = function() {
        var config = {
            "src": scriptPath + "boot.js",
            "dest": assetJsPath + "boot.min.js"
        };
        for (var key in requireJsPathConfigs) {
            if (requireJsPathConfigs.hasOwnProperty(key)
                && requireJsPathConfigs[key].substr(0, 2) === "./") {
                requireJsPathConfigs[key] = "." + requireJsPathConfigs[key];
            }
        }
        grunt.file.write(
            config.dest,
            "requirejs.config({baseUrl:SZ.JS_URL,paths:" +
                JSON.stringify(requireJsPathConfigs) +
                ",shim:" +
                JSON.stringify(requireJsShimConfigs) +
                ",priority:" +
                JSON.stringify(["angular"]) +
                "});" + "\n" +
                grunt.file.read(config.src)
        );
    };
    grunt.registerTask("Task_PrepareRequireJsConfig", Task_PrepareRequireJsConfig);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* UGLIFY JS CONFIG
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    var Task_UglifyAll = function() {
        var finalConfigs = {};
        uglifyConfigs.forEach(function(config) {
            for (var output in config.files) {
                if (config.files.hasOwnProperty(output)) {
                    var sources = [];
                    config.files[output].forEach(function(source) {
                        sources.push(path.join(config.src, source));
                    });
                    finalConfigs[path.join(config.dest, output)] = sources;
                }
            }
        });
        grunt.log.writeln("Uglify configs:");
        console.log(finalConfigs);
        grunt.config.set("uglify.all.files", finalConfigs);
        grunt.task.run("uglify:all");
    };
    grunt.registerTask("Task_UglifyAll", Task_UglifyAll);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* UGLIFY JS
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks("grunt-contrib-uglify");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* CSS LESS
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks("grunt-contrib-less");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* CSS MIN
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks("grunt-contrib-cssmin");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* HTML MIN
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks("grunt-contrib-htmlmin");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* WATCH
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    var bootChanged = false;
    var watchChangedJs = {}; // jsDest: jsSrc
    var watchChangedCss = {}; // cssDest: cssSrc
    var watchChangedHtml = {}; // htmlDest: htmlSrc

    grunt.event.on("watch", function(action, filePath) {
        var path = require("path");
        if (action === "changed") { // only handle changed files
            var fileName = path.basename(filePath);
            var extName = path.extname(fileName);
            var rawFileName = path.basename(fileName, extName);
            var pathParts = filePath.split(path.sep);
            var pathFirst = pathParts[0];
            var pathSecond = pathParts[1];
            var pathThird = pathParts[2];

            console.log(fileName, extName, rawFileName, pathParts, pathFirst, pathSecond, pathThird);

            if (pathFirst === "resources" && pathSecond === "scripts" // do nothing with not self made scripts
                && pathThird !== "libs") // do nothing with third party libs
            {
                // javascript
                if (rawFileName === "boot") {
                    // boot script
                    bootChanged = true;
                } else {
                    // non boot scripts
                    var selfMaintainedUglifyConfigs = {};
                    uglifyConfigs.forEach(function(config) {
                        if (config.src === scriptPath && config.dest === assetJsPath) {
                            // only the configs with src & dest path following this rule are self made js scripts
                            selfMaintainedUglifyConfigs = config;
                        }
                    });
                    for (var jsDest in selfMaintainedUglifyConfigs.files) {
                        if (selfMaintainedUglifyConfigs.files.hasOwnProperty(jsDest)
                            && jsDest.indexOf(rawFileName) !== -1)
                        {
                            var jsSrc = [];
                            selfMaintainedUglifyConfigs.files[jsDest].forEach(function(source) {
                                jsSrc.push(path.join(scriptPath, source));
                            });
                            jsDest = path.join(assetJsPath, jsDest);
                            if (!watchChangedJs.hasOwnProperty(jsDest)) {
                                watchChangedJs[jsDest] = jsSrc;
                            }
                        }
                    }
                }
            } else if (pathFirst === "resources" && pathSecond === "styles") {
                // css
                var cssSrc = pathParts.join(path.sep);
                pathParts.pop(); // remove the file name
                pathParts.shift(); pathParts.shift(); // remove the "resources/styles" part
                var cssDest = path.join(assetCssPath, pathParts.join(path.sep), rawFileName + ".css");
                watchChangedCss[cssDest] = cssSrc;
            } else if (pathFirst === "resources" && pathSecond === "templates") {
                // html templates
                var htmlSrc = pathParts.join(path.sep);
                pathParts.pop(); // remove the file name
                pathParts.shift(); pathParts.shift(); // remove the "resources/templates" part
                var htmlDest = path.join(assetHtmlPath, pathParts.join(path.sep), fileName);
                watchChangedHtml[htmlDest] = htmlSrc;
            }
        }
    });
    grunt.loadNpmTasks("grunt-contrib-watch");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* WATCH UPGRADE
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-var onChange = grunt.util._.debounce(function() {
    var Task_WatchUpgrade = function() {
        var anyChange = false;
        if (bootChanged) {
            Task_PrepareRequireJsConfig();
            grunt.config.set("uglify.boot", {"files": {"./js/boot.min.js": ["./js/boot.min.js"]}});
            grunt.task.run("uglify:boot");
            bootChanged = false;
            anyChange = true;
        }
        if (Object.keys(watchChangedJs).length > 0) {
            grunt.config.set("uglify.flush", {"files": watchChangedJs});
            grunt.task.run("uglify:flush");
            watchChangedJs = {};
            anyChange = true;
        }
        if (Object.keys(watchChangedCss).length > 0) {
            grunt.task.run("sprite:en_us");
            grunt.task.run("sprite:fr_fr");
            grunt.task.run("sprite:ge_ge");
            grunt.task.run("sprite:spa_spa");
            grunt.task.run("sprite:por_por");
            grunt.task.run("sprite:zh_cn");
            grunt.task.run("sprite:ru_ru");

            grunt.config.set("less.flush", {"files": watchChangedCss});
            grunt.task.run("less:flush");

            grunt.task.run("concat:en_us");
            grunt.task.run("concat:fr_fr");
            grunt.task.run("concat:ge_ge");
            grunt.task.run("concat:spa_spa");
            grunt.task.run("concat:por_por");
            grunt.task.run("concat:zh_cn");
            grunt.task.run("concat:ru_ru");
            grunt.task.run("clean:css");

            grunt.task.run("cssmin:all");

            watchChangedCss = {};
            anyChange = true;
        }
        if (Object.keys(watchChangedHtml).length > 0) {
            grunt.config.set("htmlmin.flush", {
                "options": {
                    "removeComments": true,
                    "collapseWhitespace": true,
                    "collapseBooleanAttributes": true
                },
                "files": watchChangedHtml
            });
            grunt.task.run("htmlmin:flush");
            watchChangedHtml = {};
            anyChange = true;
        }
        if (anyChange) {
            //grunt.task.run("Task_UploadAll");
        }
    };
    grunt.registerTask("Task_WatchUpgrade", Task_WatchUpgrade);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* UPLOAD
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    // var Task_UploadAll = function() {
    //     if (syncConf.isLocal) {
    //         copyDir(path.join(process.cwd(), "js"), path.join(syncConf.local, "js"));
    //         copyDir(path.join(process.cwd(), "css"), path.join(syncConf.local, "css"));
    //         copyDir(path.join(process.cwd(), "view"), path.join(syncConf.local, "view"));
    //         //copyDir(path.join(process.cwd(), "img"), path.join(syncConf.local, "img")); // currently has no compressed or created images yet
    //     } else {
    //         grunt.task.run(["sftp:all"]);
    //     }
    // };
    // grunt.registerTask("Task_UploadAll", Task_UploadAll);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* SSH
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks("grunt-ssh");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* SPRITE SMITH
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.loadNpmTasks('grunt-spritesmith');

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* @@@ DEFAULT
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.registerTask("default", "Task_Build_Without_Clean");

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* @@@ BUILD
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.registerTask("Task_Build", [
        "clean:all", "Task_Init", "Task_BowerInstall", "jshint:all",
        "Task_FlushJs", "Task_FlushCss",
        "Task_FlushHtml"//,
        //"Task_UploadAll"
    ]);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* @@@ BUILD WITHOUT CLEAN
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.registerTask("Task_Build_Without_Clean", [
        "jshint:all",
        "sprite:en_us", "sprite:fr_fr", "sprite:ge_ge", "sprite:spa_spa", "sprite:por_por", "sprite:zh_cn", "sprite:ru_ru",
        "Task_FlushJs", "Task_FlushCss",
        "Task_FlushHtml"//,
        //"Task_UploadAll"
    ]);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* @@@ DEV FLUSH JS SCRIPTS
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.registerTask("Task_FlushJs", [
        "Task_CopyComponents", "Task_PrepareRequireJsConfig", "Task_UglifyAll"
    ]);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* @@@ DEV FLUSH CSS SCRIPTS
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.registerTask("Task_FlushCss", [
        "less:all",
        "concat:en_us", "concat:fr_fr", "concat:ge_ge", "concat:spa_spa", "concat:por_por", "concat:zh_cn", "concat:ru_ru",
        "clean:css",
        "cssmin:all"
    ]);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* @@@ DEV FLUSH HTML SCRIPTS
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.registerTask("Task_FlushHtml", ["htmlmin:all"]);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* @@@ DEV FLUSH IMG SPRITE
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    grunt.registerTask("Task_FlushImgSprite", [
        "sprite:en_us",
        "sprite:fr_fr",
        "sprite:ge_ge",
        "sprite:spa_spa",
        "sprite:por_por",
        "sprite:zh_cn",
        "sprite:ru_ru"
    ]);

};
